<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
</body>
<script>

/**
 * @description 通过使用Web Worker在单独的线程中运行函数，允许长时间运行的函数不会阻塞 UI。
 * @param {*} fn 
 * @returns 
 */
  const runAsync = fn => {
  // 创建一个 work 线程
  // https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
  const worker = new Worker(
    // 使用 Blob 对象 URL 创建一个编译 JS 的字符串化。
    URL.createObjectURL(new Blob([`postMessage((${fn})());`]), {
      type: 'application/javascript; charset=utf-8'
    })
  );
  // 返回结果用异步包装
  return new Promise((res, rej) => {
    // 侦听 onmessage 事件来获取工作人员发回的数据
    worker.onmessage = ({data}) => {
      res(data), worker.terminate() // 终止 worker
    };
    // 侦听异常并抛出错误
    worker.onerror = err => {
      rej(err), worker.terminate()  // 终止 worker
    }
  })
}

// 例子
const longRunningFunction = () => {
  let result = 0;
  for (let i = 0; i < 1000; i++)
    for (let j = 0; j < 700; j++)
      for (let k = 0; k < 300; k++) result = result + i + j + k;

  return result;
};
/*
  NOTE: Since the function is running in a different context, closures are not supported.
  The function supplied to `runAsync` gets stringified, so everything becomes literal.
  All variables and functions must be defined inside.
*/
runAsync(longRunningFunction).then(console.log); // 209685000000
runAsync(() => 10 ** 3).then(console.log); // 1000
let outsideVariable = 50;
runAsync(() => typeof outsideVariable).then(console.log); // 'undefined'
</script>
</html>